import { IBaseDataType } from '../Type/CommonType';
import { ECamp } from '../Manager/CampManager';
import Base from "../Base/Base";
import CampBase from "../Camp/CampBase";
import FightManager from "../Manager/FightManager";
import { EM, EEventName } from '../Manager/EventManager';
import SkillBase from '../Skill/SkillBase';

/*
 * @features: 卡牌或角色的基类
 * @description: 说明
 * @Date: 2020-08-12 23:29:02
 * @Author: judu233(769471424@qq.com)
 * @LastEditTime: 2021-09-12 15:41:29
 * @LastEditors: judu233
 */


const { ccclass, property } = cc._decorator;

/**卡牌或角色的基础数据 */
export interface ICardDataType extends IBaseDataType {
    /**卡牌或角色的动态hp值 */
    hp: number;
    /**卡牌的上限值 */
    hpUp: number;
    /**卡牌是否死亡 */
    death: boolean;
    /**卡牌所属阵营 */
    camp: ECamp;
    /**攻击值 */
    attack: number;
    /**技能id ->类名 + 辨别值, 自动生成*/
    skillId: string;
    /**技能类名 */
    skillType: string;

}

/**  
    * @Title : 卡牌或角色的基类
    * @Description : 类说明
 **/
@ccclass
export default class CardBase extends Base {
    /**存储卡牌的数据 */
    public data: ICardDataType;

    /**卡牌技能 */
    public skill: SkillBase;

    /**显示血量的文本 */
    @property({
        type: cc.Label,
        displayName: `血量Label`,
        tooltip: `显示在界面血量的文本（没有可不拖）`,
    })
    public hpLabel_com: cc.Label = null;

    /**显示名字的文本 */
    @property({
        type: cc.Label,
        displayName: `名字Label`,
        tooltip: `显示在界面名字的文本（没有可不拖）`,
    })
    public nameLabel_com: cc.Label = null;

    /**显示血量上限的文本 */
    @property({
        type: cc.Label,
        displayName: `血量上限Label`,
        tooltip: `显示在界面血量上限的文本（没有可不拖）`,
    })
    public hpUpLabel_com: cc.Label = null;

    /**显示攻击力的文本 */
    @property({
        type: cc.Label,
        displayName: `攻击力Label`,
        tooltip: `显示在界面攻击力的文本（没有可不拖）`,
    })
    public attackLabel_com: cc.Label = null;

    //*卡牌id
    public get id(): string {
        return this.checkGet(() => {
            return this.data.id;
        });
    }
    public set id(value: string) {
        this.checkSet(() => {
            this.data.id = value;
            this.idView(this.data.id);
        });
    }
    /**id 的视图控制 */
    protected idView(value: string) { }

    //*卡牌血量
    public get hp(): number {
        return this.checkGet(() => {
            return this.data.hp;
        })
    }
    public set hp(value: number) {
        this.checkSet(() => {
            //判断hp
            if (value <= 0) {
                this.data.hp = 0;
                let camp = FightManager.campManager.getCampByName(this.camp);
                //存入死亡列表中
                if (camp) camp.delSurviveCardByName(this.id);
                else cc.warn(`[${this.className}]hp为0,把卡牌设置成死亡状态失败！`);
            } else {
                //判断血量上限
                if (value >= this.hpUp) value = this.hpUp;
                this.data.hp = value;
            }

            //视图view变动
            this.hpView(this.data.hp);

            //发送hp修改事件
            switch (this.camp) {
                case ECamp.Player:
                    EM.fire(EEventName.PlayerHpChange, this);
                    break;
                case ECamp.Computer:
                    EM.fire(EEventName.ComputerHpChange, this);
                    break;
                case ECamp.CampBase:
                    cc.warn(`请继承${this.camp}阵营，不要直接使用此阵营`);
                    break;
                default:
                    cc.warn(`没有${this.camp}阵营，请检查阵营拼写是否正确`);
            }
        });
    }
    /**hp的视图控制 */
    protected hpView(value: number) {
        if (this.hpLabel_com) this.hpLabel_com.string = `${value}`;
    }

    //*卡牌名字
    public get itemName(): string {
        return this.checkGet(() => {
            return this.data.name;
        })
    }
    public set itemName(value: string) {
        this.checkSet(() => {
            this.data.name = value;
            this.nameView(this.data.name);
        });
    }
    /**name的视图控制 */
    protected nameView(value: string) {
        if (this.nameLabel_com)  this.nameLabel_com.string = value;
    }

    //*卡牌死亡状态
    public get death(): boolean {
        return this.checkGet(() => {
            return this.data.death;
        });
    }
    public set death(value: boolean) {
        this.checkSet(() => {
            this.data.death = value;
            this.deathView(this.data.death);
        });
    }
    /**death的视图控制 */
    protected deathView(value: boolean) { }

    //*卡牌血量的上限值
    public get hpUp(): number {
        return this.checkGet(() => {
            return this.data.hpUp;
        });
    }
    public set hpUp(value: number) {
        this.checkSet(() => {
            this.data.hpUp = value;
            this.hpUpView(this.data.hpUp);
        });
    }
    /**hpUp的视图控制 */
    protected hpUpView(value: number) {
        if (this.hpUpLabel_com) this.hpUpLabel_com.string = `${value}`;
    }

    //*卡牌的阵营
    public get camp(): ECamp {
        return this.checkGet(() => {
            return this.data.camp;
        });
    }
    public set camp(value: ECamp) {
        this.checkSet(() => {
            this.data.camp = value;
            this.campView(this.data.camp);
        });
    }
    /**camp的视图控制 */
    protected campView(value: ECamp) { }

    //*卡牌攻击力
    public get attack(): number {
        return this.checkGet(() => {
            return this.data.attack;
        });
    }
    public set attack(value: number) {
        this.checkSet(() => {
            this.data.attack = value;
            this.attackView(this.data.attack);
        });
    }
    /**攻击力的视图 */
    protected attackView(value: number) {
        if (this.attackLabel_com)  this.attackLabel_com.string = `${value}`;
    }

    /**
     * //*更新卡牌的视图属性
     */
    public refreshView() {
        this.idView(this.data.id);
        this.hpView(this.data.hp);
        this.nameView(this.data.name);
        this.hpUpView(this.data.hpUp);
        this.campView(this.data.camp);
        this.deathView(this.data.death);
        this.attackView(this.data.attack);
    }

    /**初始化卡牌的技能数据 */
    public initSkill() {
        //挂载skill
        // let skill = FightManager.skillManager.getSkillDataById(this.data.skillType);
        // this.skill = skill;
        // skill.useCard = this;
    }

    //*关于卡牌的操作
    /**
     * 攻击指定阵营
     * @param camp 要攻击的阵营
     */
    public async attackCamp(camp: CampBase) {
        //自动战斗
        if (FightManager.process.isAuto || this.camp == ECamp.Computer) {
            await new Promise<void>(autoResolve => {
                let count = 1;
                Promise.all(this.attackCards(camp, count)).then(() => {
                    autoResolve();
                });
            });
        } else {
            //* 手动等待流程 && 玩家攻击
            await new Promise<void>(waitResolve => {
                //攻击单个卡牌
                EM.once(EEventName.PlayerAttack, async () => {
                    await this.attackCards(camp, 1)[0];
                    waitResolve(); //解除等待
                });
                //攻击多个卡牌
                EM.once(EEventName.PlayerSkill, async () => {
                    //等待所有攻击完成
                    Promise.all(this.attackCards(camp, 2)).then(() => {
                        waitResolve(); //解除等待
                    });
                });
            });
            //等待promise完成后
            //注销事件
            EM.off(EEventName.PlayerSkill);
            EM.off(EEventName.PlayerAttack);
        }
    }

    /**
     * 攻击指定的卡牌
     * @param card 要攻击的卡牌
     */
    public attackCard(card: CardBase) {
        return new Promise<void>((resolve) => {
            cc.log(`[${this.itemName}]卡牌开始攻击[${card.itemName}]`);
            setTimeout(() => {
                card.hp -= 300;
                cc.log(`[${this.itemName}]卡牌攻击完成[${card.itemName}]`);
                resolve();
            }, 1000);
        });
    }

    /**
     * 攻击多个卡牌(同时&&轮流)
     * @param attackCamp 要攻击的阵营
     * @param attackCount 攻击数量
     * @param isSimultaneously 是否同时攻击--默认同时
     */
    public attackCards(attackCamp: CampBase, attackCount: number, isSimultaneously: boolean = true) {
        //获取卡牌
        let cardList = attackCamp.getSurviveCardForRandom(attackCount);
        let promiseList: Promise<unknown>[] = [];

        //电脑攻击模式 -- 同时或轮流
        if (this.camp == ECamp.Computer) isSimultaneously = FightManager.process.isComputerTurnAttack;
        else if (this.camp == ECamp.Player) isSimultaneously = FightManager.process.isPlayerTurnAttack;

        if (isSimultaneously) {
            //同步攻击
            for (let card of cardList)
                promiseList.push(this.attackCard(card));
        } else {
            //异步攻击（轮流）
            let selfCamp = this;
            promiseList.push(new Promise<void>(async (resolve) => {
                for (let card of cardList)
                    await selfCamp.attackCard(card);
                //完成攻击
                resolve();
            }));
        }
        return promiseList;
    }

}
